(import
  (except (rnrs base) let-values map error)
  (only (guile) lambda* λ command-line)
  (ice-9 peg)
  (srfi srfi-1)
  (fileio))

;; GRAMMAR

(define-peg-pattern DIGIT body (range #\0 #\9))
(define-peg-pattern ALPHABET-CHAR body (range #\a #\z))

(define-peg-pattern POS1 all (+ DIGIT))
(define-peg-pattern POS2 all (+ DIGIT))
(define-peg-pattern PW-SPEC-CHAR all ALPHABET-CHAR)
(define-peg-pattern PW all (+ ALPHABET-CHAR))

(define-peg-pattern PW-LINE all
  (and POS1 "-" POS2 " " PW-SPEC-CHAR ":" " " PW))

(define get-pos1
  (λ (match-tree)
    (string->number (second (second match-tree)))))

(define get-pos2
  (λ (match-tree)
    (string->number (second (fourth match-tree)))))

(define get-spec-char
  (λ (match-tree)
    (first (string->list (second (sixth match-tree))))))

(define get-pw
  (λ (match-tree)
    (second (eighth match-tree))))

;; LOGIC

(define bxor
  (λ (a b)
    (if (or (and a b) (and (not a) (not b)))
        #f
        #t)))


(define xor
  (lambda* (. args)
    (reduce (λ (elem previous) (bxor elem previous))
            #f
            args)))


(define valid-password?
  (λ (grammar-match)
    (let* ([match-tree (peg:tree grammar-match)]
           [pos1 (get-pos1 match-tree)]
           [pos2 (get-pos2 match-tree)]
           [spec-char (get-spec-char match-tree)]
           [pw (get-pw match-tree)])
      (xor (char=? spec-char (first (string->list (substring pw (- pos1 1) pos1))))
           (char=? spec-char (first (string->list (substring pw (- pos2 1) pos2))))))))


(define main
  (λ (cmd-line-args)
    (let* ([lines (get-lines-from-file (cadr cmd-line-args))]
           [grammar-matches (map (λ (line) (match-pattern PW-LINE line)) lines)])
      (fold (λ (grammar-match accum)
              (cond
               [(valid-password? grammar-match) (+ accum 1)]
               [else accum]))
            0
            grammar-matches))))


(simple-format (current-output-port)
               "~a\n"
               (main (command-line)))
